import { AssetManager, log, resources, Prefab, Texture2D, SpriteFrame, JsonAsset, SpriteAtlas, ParticleAsset, AudioClip, assetManager, director, SceneAsset, Asset, dynamicAtlasManager, sp, Material, AnimationClip, ImageAsset, EffectAsset } from "cc";
import { IResBundle } from "../cfw/res/IResBundle";
import { ResType } from "../cfw/res/ResDefine";


export default class ResBundle implements IResBundle {
    //使用次数
    protected count: number = 0;

    //获得使用次数
    getCount() {
        return this.count;
    }

    sub() {
        this.count--;
    }

    add() {
        this.count++;
    }
    protected mgr: AssetManager.Bundle;

    // 全局资源使用计数器。用于cocos2.4.x之前的版本。
    private static resCountMap: { [uuid: string]: number } = {}

    //todo 先观察是否需要使用name
    protected name: string;
    constructor(mgr: AssetManager.Bundle, name: string = '') {
        this.mgr = mgr;
        if (!this.mgr) {
            this.mgr = resources;
        }
        this.name = name;
    }


    public addSuffix(resStr: string, suffix: string) {
        let d = resStr.length - suffix.length;
        if (d >= 0 && resStr.lastIndexOf(suffix) == d) {
            return resStr;
        }
        return resStr + suffix;
    }

    /**
      * 加载资源
      * @param url 
      * @param type 
      * @param callback 
      */
    loadRes(url: string, type: number, callback: (error: any, assets: any) => void, onProgress?: (finished: number, total: number, item?: AssetManager.RequestItem) => void): void {
        // log(' this.name ', this.name, ' type ', type)
        switch (type) {
            case ResType.Material:
                this.mgr.load(url, Material, onProgress, callback)
                break;
            case ResType.Prefab:
                this.mgr.load(url, Prefab, onProgress, callback)
                break;
            case ResType.Texture2D:
                url = this.addSuffix(url, "/texture");
                this.mgr.load(url, Texture2D, onProgress, callback)
                break;
            case ResType.SpriteFrame:
                url = this.addSuffix(url, "/spriteFrame");
                this.mgr.load(url, SpriteFrame, onProgress, callback)
                break;
            case ResType.Json:
                this.mgr.load(url, JsonAsset, onProgress, callback)
                break;
            case ResType.SpriteAtlas:
                this.mgr.load(url, SpriteAtlas, onProgress, callback)
                break;
            case ResType.Particle2D:
                this.mgr.load(url, ParticleAsset, onProgress, callback)
                break;
            case ResType.AudioClip:
                this.mgr.load(url, AudioClip, onProgress, callback)
                break;
            case ResType.AnimationClip:
                this.mgr.load(url, AnimationClip, onProgress, callback)
                break;
            case ResType.AssetBundle:
                if (onProgress) {
                    assetManager.loadBundle(url, {
                        onFileProgress: (loaded: number, total: number) => {
                            // console.log('loaded ', loaded, total)
                            onProgress(1, 1)
                        },
                    }, callback)
                } else {
                    assetManager.loadBundle(url, callback)
                }

                break;
            case ResType.Scene:
                // resources.preloadScene(url, callback)
                //log('loadRes  url ', url)
                director.preloadScene(this.name + url, onProgress, callback)

                // let func: ResCallback = (err: any, res: any) => {
                //     log(' err ==  ', err)
                //     callback(err, res)
                // }
                // this.mgr.load(url, SceneAsset, func)
                break;
            case ResType.Remote:
                if (onProgress) {
                    onProgress(1, 1)
                }
                assetManager.loadRemote(url, callback)

                break;
            case ResType.Director:
                this.mgr.loadDir(url, callback)
                break;
            case ResType.Spine:
                this.mgr.load(url, sp.SkeletonData, onProgress, callback)
                break;
        }
    }


    /**
     * 清理资源
     * @param url 
     */
    private releaseRes(asset: Asset): void {
        // loader.release(url);
        // resources.release(asset)
        assetManager.releaseAsset(asset);
    }

    //清除bundle
    clear() {

    }


    static getResType(asset: Asset): ResType {
        if (asset instanceof ImageAsset) {
            return ResType.ImageAsset;
        }
        if (asset instanceof Texture2D) {
            return ResType.Texture2D;
        }
        if (asset instanceof SpriteFrame) {
            return ResType.SpriteFrame;
        }
        if (asset instanceof AudioClip) {
            return ResType.AudioClip;
        }

        if (asset instanceof Prefab) {
            return ResType.Prefab;
        }
        if (asset instanceof AnimationClip) {
            return ResType.AnimationClip;
        }
        if (asset instanceof EffectAsset) {
            return ResType.EffectAsset;
        }
        if (asset instanceof Material) {
            return ResType.Material;
        }
        if (asset instanceof JsonAsset) {
            return ResType.Json;
        }
        if (asset instanceof SpriteAtlas) {
            return ResType.SpriteAtlas;
        }
        if (asset instanceof ParticleAsset) {
            return ResType.ParticleAsset;
        }


        return ResType.NULL
    }

    getRes(url: string, type: number): any {
        switch (type) {
            case ResType.Prefab:
                return this.mgr.get(url, Prefab);
            case ResType.Texture2D:
                // url = this.addSuffix(url, "/texture");
                return this.mgr.get(url, Texture2D);
            case ResType.SpriteFrame:
                // url = this.addSuffix(url, "/spriteFrame");
                return this.mgr.get(url, SpriteFrame);
            case ResType.Json:
                return this.mgr.get(url, JsonAsset);
            case ResType.SpriteAtlas:
                return this.mgr.get(url, SpriteAtlas);
            case ResType.Particle2D:
                return this.mgr.get(url, ParticleAsset)
            case ResType.AudioClip:
                return this.mgr.get(url, AudioClip)
            case ResType.Scene:
                return this.mgr.get(url, SceneAsset)
            case ResType.AssetBundle:
                return assetManager.getBundle(url)
            case ResType.Remote:
                return null;
            case ResType.Spine:
                return this.mgr.get(url, sp.SkeletonData)
            case ResType.Director:
                return null;
            case ResType.AnimationClip:
                return this.mgr.get(url, AnimationClip)
            default:
                console.error(' getRes error url is ', url, ' type is ', type)
                return null;
        }

    }

    private getDependsRecursively(res: any): any {
        // return loader.getDependsRecursively(res)
        return []
    }

    addRes(res: any): void {
        if (res) {
            if (res instanceof Asset) {
                res.addRef()
            } else if (res instanceof Array) {
                for (let index = 0; index < res.length; index++) {
                    const r: Asset = res[index];
                    r.addRef();
                }
            }

        }
    }

    decRes(res: any): void {
        if (res) {
            if (res instanceof Asset) {
                res.decRef()
            } else if (res instanceof Array) {
                for (let index = 0; index < res.length; index++) {
                    const r: Asset = res[index];
                    r.decRef();
                }
            }

        }
    }

    private addRef(res: any) {
        let key = ''
        if (!ResBundle.resCountMap[key]) {
            ResBundle.resCountMap[key] = 0
        }
        ResBundle.resCountMap[key]++;
        let list = this.getDependsRecursively(res);
        for (let index = 0; index < list.length; index++) {
            const element = list[index];
            this.addRef(element)
        }
    }

    private decRef(res: any) {
        let key = ''
        if (ResBundle.resCountMap[key] > 0) {
            ResBundle.resCountMap[key]--;

            if (ResBundle.resCountMap[key] == 0) {
                // console.log('subCount ResItem.resCountMap[key] ', key, ' key ', ResItem.resCountMap[key])

                delete ResBundle.resCountMap[key];
            }
        }
        let list = this.getDependsRecursively(res);
        for (let index = 0; index < list.length; index++) {
            const element = list[index];
            this.decRef(element)
        }
    }

    resCount(res: Asset): number {
        if (res) {
            if (res instanceof Asset) {
                return res.refCount;
            } else {
                log(' res is not asset ', typeof (res))
            }

        }
        return 0;
    }

}